package main

import (
	"bytes"
	"context"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"github.com/emmansun/gmsm/sm4"
	"github.com/wailsapp/wails/v2/pkg/runtime"
	"gopkg.in/ini.v1"
	"io"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"syscall"
	"time"

	"gitee.com/Trisia/gotlcp/https"
	"gitee.com/Trisia/gotlcp/tlcp"
)

const (
	INI_NAME = "\\.caiwu\\.caiwu.ini"
)

type ConfigItem struct {
	Name string   `json:"name"`
	Tags []string `json:"tags"`
}

// App struct
type App struct {
	ctx        context.Context
	cmd        *exec.Cmd
	isRunning  bool
	mu         sync.Mutex
	TLCPClient *http.Client
}

// NewApp creates a new App application struct
func NewApp() *App {
	return &App{}
}

// startup is called when the app starts. The context is saved
// so we can call the runtime methods
func (a *App) startup(ctx context.Context) {
	a.ctx = ctx
	a.TLCPClient = https.NewHTTPSClient(&tlcp.Config{InsecureSkipVerify: true})

}
func (a *App) shutdown(ctx context.Context) {
	err := a.CloseChat()
	fmt.Printf("关闭进程: %v\n", err)
	if err != nil {
		return
	}
}

// 选择Excel文件
func (a *App) SelectFiles() []string {
	selection, err := runtime.OpenMultipleFilesDialog(a.ctx, runtime.OpenDialogOptions{
		Title: "选择Excel文件",
		Filters: []runtime.FileFilter{
			{
				DisplayName: "Excel Files",
				Pattern:     "*.xlsx;*.xls",
			},
		},
	})
	if err != nil {
		return []string{}
	}
	return selection
}

// 选择保存路径
func (a *App) SelectSavePath() string {
	path, err := runtime.OpenDirectoryDialog(a.ctx, runtime.OpenDialogOptions{
		Title: "选择保存目录",
	})
	if err != nil {
		return ""
	}
	return path
}

// 新增保存方法
func (a *App) SaveToFile(files []string, savePath string) string {
	// 获取桌面路径
	homeDir, _ := os.UserHomeDir()
	outputPath := filepath.Join(homeDir, "Desktop", "aaa.txt")

	// 准备写入内容
	content := new(strings.Builder)
	content.WriteString("=== 文件列表 ===\n")
	for _, file := range files {
		content.WriteString(file + "\n")
	}
	content.WriteString("\n=== 保存路径 ===\n")
	content.WriteString(savePath + "\n")

	// 写入文件
	err := os.WriteFile(outputPath, []byte(content.String()), 0644)
	if err != nil {
		return fmt.Sprintf("保存失败: %v", err)
	}
	return "保存成功"
}

// 加载配置
func (a *App) LoadConfig() ([]ConfigItem, error) {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		fmt.Printf("获取用户目录失败: %v\n", err)
		return []ConfigItem{}, nil
	}
	cfg, err := ini.Load(homeDir + INI_NAME)
	if os.IsNotExist(err) {
		return []ConfigItem{}, nil
	}
	if err != nil {
		return nil, err
	}

	var items []ConfigItem
	for _, section := range cfg.Sections() {
		if section.Name() == "DEFAULT" {
			continue
		}
		items = append(items, ConfigItem{
			Name: section.Name(),
			Tags: strings.Split(section.Key("tags").String(), ","),
		})
	}
	return items, nil
}

// 保存配置
func (a *App) SaveConfig(items []ConfigItem) error {
	cfg := ini.Empty()
	for _, item := range items {
		section, _ := cfg.NewSection(item.Name)
		section.NewKey("tags", strings.Join(item.Tags, ","))
	}
	homeDir, err := os.UserHomeDir()
	if err != nil {
		fmt.Printf("获取用户目录失败: %v\n", err)
		return err
	}
	return cfg.SaveTo(homeDir + INI_NAME)
}

// 打开机器人
func (p *App) OpenChat(listen string) error {
	p.mu.Lock()
	defer p.mu.Unlock()

	if p.isRunning {
		return nil // 避免重复启动
	}
	fmt.Printf("监听对象: %v\n", listen)
	// 创建命令对象（示例为Windows可执行文件）
	p.cmd = exec.Command("dist/chatbot/chatbot.exe", listen)

	// 设置隐藏CMD窗口（Windows平台）
	p.cmd.SysProcAttr = &syscall.SysProcAttr{
		HideWindow:    true,       // 隐藏窗口[7,8](@ref)
		CreationFlags: 0x08000000, // 使用CREATE_NO_WINDOW标志[4,6](@ref)
	}

	// 异步启动进程
	if err := p.cmd.Start(); err != nil {
		return err
	}

	// 监听进程状态（关键）
	go func() {
		_ = p.cmd.Wait() // 回收系统资源
		p.mu.Lock()
		p.isRunning = false
		p.mu.Unlock()
	}()

	p.isRunning = true
	return nil
}

func (p *App) CloseChat() error {
	p.mu.Lock()
	defer p.mu.Unlock()

	if p.cmd == nil || p.cmd.Process == nil {
		return nil
	}

	// 强制终止进程树（跨平台兼容）
	if err := p.cmd.Process.Kill(); err != nil {
		return err
	}

	p.isRunning = false
	p.cmd = nil // 释放资源
	return nil
}

// GetWithTLCP 带Header的GET请求[1](@ref)
func (p *App) GetWithTLCP(url string) (string, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return "", err
	}
	headers := map[string]string{
		"User-Agent": "TLCP-Client/1.0",
	}
	// 设置请求头
	for k, v := range headers {
		req.Header.Set(k, v)
	}

	resp, err := p.TLCPClient.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	all, err := io.ReadAll(resp.Body)
	return string(all), err
}

// PostJsonWithTLCP 发送JSON数据的POST请求[6,8](@ref)
func (p *App) PostJsonWithTLCP(url string, data string, method string) (string, error) {

	fmt.Printf("请求信息: %v\n", data)

	req, err := http.NewRequest(method, url, bytes.NewReader([]byte(data)))
	if err != nil {
		return "", err
	}

	// 设置默认请求头
	req.Header.Set("Content-Type", "application/json")
	headers := map[string]string{
		"User-Agent": "TLCP-Client/1.0",
	}
	// 设置请求头
	for k, v := range headers {
		req.Header.Set(k, v)
	}

	resp, err := p.TLCPClient.Do(req)
	if err != nil {
		return "", nil
	}
	defer resp.Body.Close()
	all, err := io.ReadAll(resp.Body)
	return string(all), err
}

// 生成随机密钥（参考网页3、5）
func (f *App) GenerateRandomKey() (string, error) {
	key := make([]byte, 16)
	if _, err := rand.Read(key); err != nil {
		return "", err
	}
	return hex.EncodeToString(key), nil
}

// 选择待加密文件
func (f *App) SelectSourceFile() string {
	selection, _ := runtime.OpenFileDialog(f.ctx, runtime.OpenDialogOptions{
		Title: "选择待加密文件",
		Filters: []runtime.FileFilter{
			{
				DisplayName: "Zip Files",
				Pattern:     "*.zip",
			},
		},
	})
	return selection
}

// 带时间戳的加密（核心方法）
func (f *App) EncryptWithTimestamp(srcPath string, targetDir string, keyStr string) (string, error) {
	if srcPath == "" || targetDir == "" {
		return "", fmt.Errorf("路径不能为空")
	}

	// 生成时间戳文件名（网页13方案）
	timestamp := time.Now().Format("20060102150405")
	baseName := filepath.Base(srcPath)
	newName := fmt.Sprintf("%s_%s.zip", baseName[:len(baseName)-len(filepath.Ext(baseName))], timestamp)
	dstPath := filepath.Join(targetDir, newName)

	// 调用原有加密逻辑
	if err := EncryptFile(srcPath, dstPath, keyStr); err != nil {
		return "", fmt.Errorf("加密失败: %v", err)
	}
	return dstPath, nil
}

// 生成SM4密钥
func initKey(keyStr string) ([]byte, error) {
	return hex.DecodeString(keyStr) // HEX转字节[1](@ref)
}

// 加密文件 (ECB模式)
func EncryptFile(srcPath, dstPath string, keyStr string) error {
	key, err := initKey(keyStr)
	if err != nil {
		return fmt.Errorf("密钥解析失败: %v", err)
	}

	// 读取源文件
	srcFile, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	// 创建目标文件
	dstFile, err := os.Create(dstPath)
	if err != nil {
		return err
	}
	defer dstFile.Close()

	// 创建SM4加密器（ECB模式）[6](@ref)
	cipher, err := sm4.NewCipher(key)
	if err != nil {
		return fmt.Errorf("创建加密器失败: %v", err)
	}

	// 逐块加密（ECB模式无需IV）
	buf := make([]byte, sm4.BlockSize)
	for {
		n, err := srcFile.Read(buf)
		if err == io.EOF {
			break
		} else if err != nil {
			return err
		}

		// 处理最后一块的PKCS5填充[1](@ref)
		if n < sm4.BlockSize {
			padding := sm4.BlockSize - n
			buf = append(buf[:n], bytes.Repeat([]byte{byte(padding)}, padding)...)
		}

		// 执行加密
		cipher.Encrypt(buf, buf)
		if _, err := dstFile.Write(buf); err != nil {
			return err
		}
	}
	return nil
}
